第十章 信号

Huan Lee Lv5

Untitled

10.1 Linux信号概述

Linux下, 一个进程给其他进程发送信号的API是kill函数

1
2
3
#include <sys/types.h>
#include <signal.h>
int kill(pid_t pid, int sig);

Untitled

信号处理方式

目标进程在收到信号时, 需要定义一个接收函数来处理.

1
typedef void(*__sighandler_t) (int); // 定义一个函数名

该函数只有一个整型参数, 表示信号类型.

bits/signum.h头文件中还定义了i新年好的两种其他处理方式. SIG_IGN表示忽略目标信号, SIG_DFL表示使用信号的默认处理方式.

1
2
3
#include <bits/signum.h>
#define SIG_DFL ((__sighandler_t) 0)
#define SIG_IGN ((__sighandler_t) 1)

Linux信号

默认处理方式:

  • 结束进程-Term
  • 忽略信号-Ign
  • 结束进程并生成核心转储文件-Core
  • 暂停进程-Stop
  • 继续进程-Cont

Linux的可用信号都定义在bits/signum.h中.

Untitled

Untitled

与网络编程紧密相关的又SIGHUP, SIGPIPE, SIGURG.

中断系统调用

程序在执行处于阻塞状态的系统调用时收到信号, 并且设置了信号处理函数, 则默认情况下系统调用会被中断, 且errno为EINTR. 可以使用sigaction函数为信号设置SA_RESTART标志以自动重启被中断的系统调用.

10.2 信号函数

1
2
#include<signal.h>
_sighandler_t signal(int sig, _sighandler_t _handler)
  • sig指定捕获的信号类型;_handler参数是_sighandler_t类型的函数指针, 指定信号sig的处理函数
1
int sigaction(int sig, const struct sigaction* act, struct sigaction* oact);

sigaction系统调用是更健壮(?)的接口.

  • act指定新的信号处理方式; oact输出信号先前的处理方式.
  • sigaction结构体中, sa_handler成员指定信号处理函数; sa_mask设置进程的信号掩码; sa_flags设置程序收到信号时的行为

Untitled

10.3 信号集

Linux用数据结构sigset_t来表示一组信号, 其实际上时一个长整型数组, 数组的每个元素的每个位表示一个信号.

1
2
3
4
5
#include <bits/sigset.h>
#define _SIGSET_NWORDS(1024/(8*sizeof(unsigned long int)))
typedef struct {
unsigned long int __val[_SIGSET_NWORDS];
} __sigset_t;

Linux提供了一组简化位运算的函数:

Untitled

进程信号掩码

信号掩码可以指定哪些信号不能发送给本进程.

1
2
#include<signal.h>
int sigprocmask(int _how, _const sigset_t* _set, sigset_t* _oset);

Untitled

被挂起的信号

信号掩码会导致被屏蔽的信号不能被进程接收, OS会将这些信号设置为进程的一个被挂起的信号. 如果我们取消对被挂起信号的屏蔽, 则它能立即被进程收到, 如下函数能够获得进程当前被挂起的信号集

1
int sigpending(sigset_t* set);

10.4 统一事件源

信号是一种异步事件:信号处理函数和程序的主循环是两条不同的执行路线。很显然,信号处理函数需要尽可能快地执行完毕,以确保该信号不被屏蔽(前面提到过,为了避免
一些竞态条件,信号在处理期间,系统不会再次触发它)太久。一种典型的解决方案是:
把信号的主要处理逻辑放到程序的主循环中,当信号处理函数被触发时,它只是简单地通
知主循环程序接收到信号,并把信号值传递给主循环,主循环再根据接收到的信号值执行
目标信号对应的逻辑代码。信号处理函数通常使用管道来将信号“传递”给主循环:信号
处理函数往管道的写端写入信号值,主循环则从管道的读端读出该信号值。那么主循环怎
么知道管道上何时有数据可读呢?这很简单,我们只需要使用/O复用系统调用来监听管
道的读端文件描述符上的可读事件。如此一来,信号事件就能和其他I/O事件一样被处理,
即统一事件源。

10.5 网络编程相关信号

SIGHUP

当挂起进程的控制终端时,SIGHUP信号将被触发。对于没有控制终端的网络后台程序而言,它们通常利用SIGHUP信号来强制服务器重读配置文件。

SIGPIPE

默认情况下,往一个读端关闭的管道或socket连接中写数据将引发SIGPIPE信号。我们需要在代码中捕获并处理该信号,或者至少忽略它,因为程序接收到SIGPIPE信号的默认行为是结束进程,而我们绝对不希望因为错误的写操作而导致程序退出。引起SIGPIPE信号的写操作将设置errno为EPIPE。

SIGURG

SIGURG信号是内核通知应用程序带外数据到达的两种方式之一(另一种是处理socket系统调用的异常事件)

  • Title: 第十章 信号
  • Author: Huan Lee
  • Created at : 2023-08-20 08:08:10
  • Updated at : 2024-02-26 04:53:15
  • Link: https://www.mirthfullee.com/2023/08/20/notion-第十章 信号-b2fb3ea2/
  • License: This work is licensed under CC BY-NC-SA 4.0.